/*
 * jxController Project (2015)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2015
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxController.view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.sql.SQLException;

import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;

import org.jxController.view.component.DriverComboBox;
import org.jxDao.dao.Conn;
import org.jxDao.dao.db.DBInfo;
import org.jxDao.dao.db.Driver;
import org.jxSwing.component.button.DeleteButton;
import org.jxSwing.component.button.OpenButton;
import org.jxSwing.component.button.SaveButton;
import org.jxSwing.component.chooser.FileChooser;
import org.jxSwing.component.dialog.ExceptionDialog;
import org.jxSwing.component.frame.Frame;
import org.jxSwing.component.text.IPv4Field;
import org.jxSwing.component.text.NumberField;
import org.jxSwing.component.text.PasswordField;
import org.jxSwing.component.text.TextField;
import org.jxSwing.i18n.I18N;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxController
 * @package org.jxController.view
 * @date 16/02/2015 - 19:10:37
 */
public abstract class ConnectionFrame extends Frame {
	
	private static final long serialVersionUID = -513839238676624827L;
	
	private JLabel lblDriver;
	
	private DriverComboBox cbxDriver;
	
	private JLabel lblHost;
	
	private IPv4Field txtHost;
	
	private JLabel lblPort;
	
	private NumberField txtPort;
	
	private JLabel lblDatabase;
	
	private TextField txtDatabase;
	
	private JLabel lblUser;
	
	private TextField txtUser;
	
	private JLabel lblPassword;
	
	private PasswordField txtPassword;
	
	private SaveButton btnSave;
	
	private DeleteButton btnCancel;
	
	private JProgressBar progressBar;
	
	private DBInfo dbInfo;
	
	private OpenButton btnSelectDatabase;
	
	/**
	 * 
	 */
	public ConnectionFrame() {
	
		this("");
	}
	
	/**
	 * @param dbInfo
	 */
	public ConnectionFrame(final DBInfo dbInfo) {
	
		this(null, dbInfo);
	}
	
	/**
	 * @param title
	 */
	public ConnectionFrame(final String title) {
	
		this(title, null);
	}
	
	/**
	 * @param title
	 * @param dbInfo
	 */
	public ConnectionFrame(final String title, final DBInfo dbInfo) {
	
		super(title);
		
		this.dbInfo = dbInfo;
		
		initGUI();
	}
	
	/**
	 * 
	 */
	private void initGUI() {
	
		getContentPane().setLayout(null);
		getContentPane().add(getLblDriver());
		getContentPane().add(getCbxDriver());
		getContentPane().add(getLblHost());
		getContentPane().add(getLblPort());
		getContentPane().add(getTxtHost());
		getContentPane().add(getTxtPort());
		getContentPane().add(getLblDatabase());
		getContentPane().add(getTxtDatabase());
		getContentPane().add(getBtnSelectDatabase());
		getContentPane().add(getLblUser());
		getContentPane().add(getTxtUser());
		getContentPane().add(getLblPassword());
		getContentPane().add(getTxtPassword());
		getContentPane().add(getBtnSave());
		getContentPane().add(getBtnCancel());
		getContentPane().add(getProgressBar());
		
		setResizable(false);
		setDBInfo(dbInfo);
		setSize(280, 380);
		centralize();
	}
	
	/**
	 * @return dbInfo or null
	 */
	private DBInfo isValidate() {
	
		final DBInfo dbInfo = new DBInfo(getCbxDriver().getSelectedItem());
		
		dbInfo.setHost(getTxtHost().getText().trim());
		dbInfo.setPort(getTxtPort().getText().trim());
		dbInfo.setDatabase(getTxtDatabase().getText().trim());
		dbInfo.setUser(getTxtUser().getText().trim());
		dbInfo.setPassword(new String(getTxtPassword().getPassword()));
		
		try {
			//
			new Conn(dbInfo);
			
			return dbInfo;
			
		}catch(ClassNotFoundException | SQLException exception) {
			
			lockField(false);
			
			getProgressBar().setIndeterminate(false);
			
			ExceptionDialog.showMessage(exception);
		}
		
		return null;
	}
	
	/**
	 * @param lock
	 */
	private void lockField(final boolean lock) {
	
		getCbxDriver().setEnabled( !lock);
		getTxtHost().setEnabled( !lock);
		getTxtPort().setEnabled( !lock);
		getTxtDatabase().setEnabled( !lock);
		getTxtUser().setEnabled( !lock);
		getTxtPassword().setEnabled( !lock);
		getProgressBar().setIndeterminate(lock);
	}
	
	/**
	 * @param driver
	 */
	private void makeDatabaseField(final Driver driver) {
	
		//
		if(driver.equals(Driver.DERBY) || driver.equals(Driver.FIREBIRD) || driver.equals(Driver.SQLITE)) {
			
			getTxtDatabase().setEditable(false);
			getTxtDatabase().setSize(220, (int)getTxtDatabase().getSize().getHeight());
			getBtnSelectDatabase().setVisible(true);
			
		}else {
			
			getTxtDatabase().setEditable(true);
			getTxtDatabase().setSize(250, (int)getTxtDatabase().getSize().getHeight());
			getBtnSelectDatabase().setVisible(false);
		}
	}
	
	/**
	 * @param dbInfo
	 * @throws Throwable
	 */
	protected abstract void save(DBInfo dbInfo) throws Throwable;
	
	public final DeleteButton getBtnCancel() {
	
		if(btnCancel == null) {
			btnCancel = new DeleteButton();
			btnCancel.setToolTipText(I18N.component().cancel());
			btnCancel.setText(btnCancel.getToolTipText());
			btnCancel.setBounds(140, 290, 120, 30);
			btnCancel.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(final ActionEvent actionEvent) {
				
					exitAction();
				}
			});
		}
		return btnCancel;
	}
	
	public final SaveButton getBtnSave() {
	
		if(btnSave == null) {
			btnSave = new SaveButton();
			btnSave.setText(btnSave.getToolTipText());
			btnSave.setBounds(10, 290, 120, 30);
			btnSave.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(final ActionEvent actionEvent) {
				
					lockField(true);
					
					new Thread(new Runnable() {
						
						@Override
						public void run() {
						
							try {
								//
								final DBInfo info = isValidate();
								
								//
								if(info != null) {
									
									getProgressBar().setIndeterminate(false);
									
									dbInfo = info;
									
									save(dbInfo);
									
									showExitQuestion(false);
									
									exitAction();
								}
								
							}catch(final Throwable throwable) {
								
								getProgressBar().setIndeterminate(false);
								
								ExceptionDialog.showMessage(throwable);
							}
						}
					}).start();
				}
			});
		}
		return btnSave;
	}
	
	public OpenButton getBtnSelectDatabase() {
	
		if(btnSelectDatabase == null) {
			btnSelectDatabase = new OpenButton();
			btnSelectDatabase.setVisible(false);
			btnSelectDatabase.setBounds(235, 140, 25, 25);
			btnSelectDatabase.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(final ActionEvent actionEvent) {
				
					final FileChooser chooser = new FileChooser();
					
					chooser.setMultiSelectionEnabled(false);
					
					//
					if(chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
						
						getTxtDatabase().setText(chooser.getSelectedFile().getAbsolutePath());
					}
				}
			});
		}
		return btnSelectDatabase;
	}
	
	public final DriverComboBox getCbxDriver() {
	
		if(cbxDriver == null) {
			cbxDriver = new DriverComboBox();
			cbxDriver.setBounds(10, 30, 250, 25);
			cbxDriver.addItemListener(new ItemListener() {
				
				@Override
				public void itemStateChanged(final ItemEvent itemEvent) {
				
					//
					if(itemEvent.getStateChange() == ItemEvent.SELECTED) {
						
						getTxtPort().setText(Driver.getDefaultPort(getCbxDriver().getSelectedItem()));
						
						getTxtDatabase().setText("");
						
						makeDatabaseField(getCbxDriver().getSelectedItem());
					}
				}
			});
		}
		return cbxDriver;
	}
	
	/**
	 * @return the dbInfo
	 */
	public final DBInfo getDBInfo() {
	
		return dbInfo;
	}
	
	public final JLabel getLblDatabase() {
	
		if(lblDatabase == null) {
			lblDatabase = new JLabel(I18N.component().dataBase() + ":");
			lblDatabase.setBounds(10, 120, 250, 15);
		}
		return lblDatabase;
	}
	
	public final JLabel getLblDriver() {
	
		if(lblDriver == null) {
			lblDriver = new JLabel(I18N.component().dbms() + ":");
			lblDriver.setBounds(10, 10, 250, 15);
		}
		return lblDriver;
	}
	
	public final JLabel getLblHost() {
	
		if(lblHost == null) {
			lblHost = new JLabel(I18N.component().hostIP() + ":");
			lblHost.setBounds(10, 65, 140, 15);
		}
		return lblHost;
	}
	
	public final JLabel getLblPassword() {
	
		if(lblPassword == null) {
			lblPassword = new JLabel(I18N.component().password() + ":");
			lblPassword.setBounds(10, 230, 250, 15);
		}
		return lblPassword;
	}
	
	public final JLabel getLblPort() {
	
		if(lblPort == null) {
			lblPort = new JLabel(I18N.component().port() + ":");
			lblPort.setBounds(160, 65, 100, 15);
		}
		return lblPort;
	}
	
	public final JLabel getLblUser() {
	
		if(lblUser == null) {
			lblUser = new JLabel(I18N.component().user() + ":");
			lblUser.setBounds(10, 175, 250, 15);
		}
		return lblUser;
	}
	
	public JProgressBar getProgressBar() {
	
		if(progressBar == null) {
			progressBar = new JProgressBar();
			progressBar.setBounds(10, 335, 250, 10);
		}
		return progressBar;
	}
	
	public final TextField getTxtDatabase() {
	
		if(txtDatabase == null) {
			txtDatabase = new TextField();
			txtDatabase.setBounds(10, 140, 250, 25);
			txtDatabase.addKeyListener(new KeyAdapter() {
				
				@Override
				public void keyPressed(final KeyEvent keyEvent) {
				
					//
					if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
						
						getTxtUser().requestFocusInWindow();
					}
				}
			});
		}
		return txtDatabase;
	}
	
	public final IPv4Field getTxtHost() {
	
		if(txtHost == null) {
			txtHost = new IPv4Field();
			txtHost.setSize(140, 25);
			txtHost.setLocation(10, 85);
			txtHost.addKeyListener(new KeyAdapter() {
				
				@Override
				public void keyPressed(final KeyEvent keyEvent) {
				
					//
					if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
						
						getTxtPort().requestFocusInWindow();
					}
				}
			});
		}
		return txtHost;
	}
	
	public final PasswordField getTxtPassword() {
	
		if(txtPassword == null) {
			txtPassword = new PasswordField();
			txtPassword.setBounds(10, 250, 250, 25);
			txtPassword.addKeyListener(new KeyAdapter() {
				
				@Override
				public void keyPressed(final KeyEvent keyEvent) {
				
					//
					if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
						
						getBtnSave().requestFocusInWindow();
					}
				}
			});
		}
		return txtPassword;
	}
	
	public final NumberField getTxtPort() {
	
		if(txtPort == null) {
			txtPort = new NumberField();
			txtPort.setText("");
			txtPort.setHorizontalAlignment(SwingConstants.CENTER);
			txtPort.setBounds(160, 85, 100, 25);
			txtPort.addKeyListener(new KeyAdapter() {
				
				@Override
				public void keyPressed(final KeyEvent keyEvent) {
				
					//
					if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
						
						getTxtDatabase().requestFocusInWindow();
					}
				}
			});
		}
		return txtPort;
	}
	
	public final TextField getTxtUser() {
	
		if(txtUser == null) {
			txtUser = new TextField();
			txtUser.setBounds(10, 195, 250, 25);
			txtUser.addKeyListener(new KeyAdapter() {
				
				@Override
				public void keyPressed(final KeyEvent keyEvent) {
				
					//
					if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
						
						getTxtPassword().requestFocusInWindow();
					}
				}
			});
		}
		return txtUser;
	}
	
	/**
	 * @return the dbInfo
	 * @throws Throwable
	 */
	public abstract DBInfo load() throws Throwable;
	
	/**
	 * @param dbInfo
	 *        the dbInfo to set
	 */
	public final void setDBInfo(final DBInfo dbInfo) {
	
		this.dbInfo = dbInfo;
		
		//
		if(dbInfo != null) {
			
			getCbxDriver().setSelectedItem(getDBInfo().getDriver());
			getTxtHost().setText(getDBInfo().getHost());
			getTxtPort().setText(getDBInfo().getPort());
			getTxtDatabase().setText(getDBInfo().getDatabase());
			getTxtUser().setText(getDBInfo().getUser());
			getTxtPassword().setText(getDBInfo().getPassword());
		}
	}
}
